package api

import (
	"animal/octopus/common"
	"animal/octopus/core"
	"encoding/csv"
	"fmt"
	"net/http"

	"github.com/gin-gonic/gin"

	log "github.com/sirupsen/logrus"
)

// ------------------------------------------------------------------------------
//
// ------------------------------------------------------------------------------
func GetChildren(c *gin.Context) {
	log.WithFields(log.Fields{"request": c.Request}).Info(c.Request.URL.Path)

	parent, err := common.GetRequestIntParam(c, "parent")
	if err != nil {
		c.PureJSON(http.StatusBadRequest, gin.H{
			"code":   common.ErrInvalidParam,
			"msg":    err.Error(),
			"result": nil,
		})
		return
	}

	if moduleInfos, err := core.GetChildren(uint(parent)); err != nil {
		c.PureJSON(http.StatusInternalServerError, gin.H{
			"code":    0,
			"type":    "success",
			"message": "success",
			"result":  nil,
		})
	} else {
		c.PureJSON(http.StatusOK, gin.H{
			"code":    0,
			"type":    "success",
			"message": "success",
			"result":  moduleInfos,
		})
	}
}

// ------------------------------------------------------------------------------
//
// ------------------------------------------------------------------------------
func GetDescendants(c *gin.Context) {
	log.WithFields(log.Fields{"request": c.Request}).Info(c.Request.URL.Path)

	root, err := common.GetRequestIntParam(c, "root")
	if err != nil {
		c.PureJSON(http.StatusBadRequest, gin.H{
			"code":   common.ErrInvalidParam,
			"msg":    err.Error(),
			"result": nil,
		})
		return
	}

	moduleInfos, err := core.GetDescendants(uint(root))
	if err != nil {
		c.PureJSON(http.StatusInternalServerError, gin.H{
			"code":    0,
			"type":    "failed",
			"message": "failed",
			"result":  nil,
		})
	} else {
		c.PureJSON(http.StatusOK, gin.H{
			"code":    0,
			"type":    "success",
			"message": "success",
			"result":  moduleInfos,
		})
	}
}

// ------------------------------------------------------------------------------
//
// ------------------------------------------------------------------------------
func CreateModule(c *gin.Context) {
	log.WithFields(log.Fields{"request": c.Request}).Info(c.Request.URL.Path)

	var param common.CreateModuleParam
	if err := c.ShouldBindJSON(&param); err != nil {
		c.PureJSON(http.StatusBadRequest, gin.H{
			"code":    0,
			"message": "error",
			"result":  nil,
		})
		log.WithField("error", err).Error("invalid request")
		return
	}

	if moduleID, err := core.CreateModule(nil, param); err != nil {
		c.PureJSON(http.StatusInternalServerError, gin.H{
			"code":    err.(*common.ErrCode).Code,
			"message": err.(*common.ErrCode).Message,
			"result":  nil,
		})
	} else {
		c.PureJSON(http.StatusOK, gin.H{
			"code":    0,
			"message": "success",
			"result": common.CreateModuleRspData{
				ID: moduleID,
			},
		})
	}
}

// ------------------------------------------------------------------------------
//
// ------------------------------------------------------------------------------
func EditModule(c *gin.Context) {
	log.WithFields(log.Fields{"request": c.Request}).Info(c.Request.URL.Path)

	var param common.EditModuleParam
	if err := c.ShouldBindJSON(&param); err != nil {
		c.PureJSON(http.StatusBadRequest, gin.H{
			"code":    0,
			"message": "error",
			"result":  nil,
		})
		log.WithField("error", err).Error("invalid request")
		return
	}

	if err := core.EditModule(nil, param); err != nil {
		c.PureJSON(http.StatusInternalServerError, gin.H{
			"code":    err.(*common.ErrCode).Code,
			"message": err.(*common.ErrCode).Message,
			"result":  nil,
		})
	} else {
		c.PureJSON(http.StatusOK, gin.H{
			"code":    0,
			"message": "success",
			"result":  nil,
		})
	}
}

// ------------------------------------------------------------------------------
//
// ------------------------------------------------------------------------------
func BatchEditModule(c *gin.Context) {
	log.WithFields(log.Fields{"request": c.Request}).Info(c.Request.URL.Path)

	var param common.BatchEditModuleParam
	if err := c.ShouldBindJSON(&param); err != nil {
		c.PureJSON(http.StatusBadRequest, gin.H{
			"code":    0,
			"message": "error",
			"result":  nil,
		})
		log.WithField("error", err).Error("invalid request")
		return
	}

	if err := core.BatchEditModule(nil, param); err != nil {
		c.PureJSON(http.StatusInternalServerError, gin.H{
			"code":    err.(*common.ErrCode).Code,
			"message": err.(*common.ErrCode).Message,
			"result":  nil,
		})
	} else {
		c.PureJSON(http.StatusOK, gin.H{
			"code":    0,
			"message": "success",
			"result":  nil,
		})
	}
}

// ------------------------------------------------------------------------------
//
// ------------------------------------------------------------------------------
func DeleteModule(c *gin.Context) {
	log.WithFields(log.Fields{"request": c.Request}).Info(c.Request.URL.Path)

	var param common.DeleteModuleParam
	if err := c.ShouldBindJSON(&param); err != nil {
		c.PureJSON(http.StatusBadRequest, gin.H{
			"code":   common.ErrInvalidParam,
			"msg":    "invalid param",
			"result": nil,
		})
		log.WithField("error", err).Error("invalid request")
		return
	}

	if core.DeleteModule(nil, param) != nil {
		c.PureJSON(http.StatusInternalServerError, gin.H{
			"code":    1,
			"message": "failed",
			"result":  nil,
		})
	} else {
		c.PureJSON(http.StatusOK, gin.H{
			"code":    0,
			"message": "success",
			"result":  nil,
		})
	}
}

// ------------------------------------------------------------------------------
//
// ------------------------------------------------------------------------------
func Report(c *gin.Context) {
	log.WithFields(log.Fields{"request": c.Request}).Info(c.Request.URL.Path)

	var info common.ReportInfo
	if err := c.ShouldBindJSON(&info); err != nil {
		c.PureJSON(http.StatusBadRequest, gin.H{
			"code":   common.ErrInvalidParam,
			"msg":    "invalid param",
			"result": nil,
		})
		log.WithField("error", err).Error("invalid request")
		return
	}

	if core.Report(nil, info) != nil {
		c.PureJSON(http.StatusInternalServerError, gin.H{
			"code":    1,
			"message": "failed",
			"result":  nil,
		})
	} else {
		c.PureJSON(http.StatusOK, gin.H{
			"code":    0,
			"message": "success",
			"result":  nil,
		})
	}
}

// ------------------------------------------------------------------------------
//
// ------------------------------------------------------------------------------
func ImportModule(c *gin.Context) {
	log.WithFields(log.Fields{"request": c.Request}).Info(c.Request.URL.Path)

	fileHeader, err := c.FormFile("file")
	if err != nil {
		c.PureJSON(http.StatusBadRequest, gin.H{
			"code":    common.ErrGeneralError,
			"message": "get file failed",
			"result":  nil,
		})
		return
	}

	file, err := fileHeader.Open()
	if err != nil {
		c.PureJSON(http.StatusInternalServerError, gin.H{
			"code":    common.ErrGeneralError,
			"message": "open file failed",
			"result":  nil,
		})
		log.WithField("error", err).Error("open file failed")
		return
	}
	defer file.Close()

	records, err := csv.NewReader(file).ReadAll()
	if err != nil {
		c.PureJSON(http.StatusInternalServerError, gin.H{
			"code":    common.ErrGeneralError,
			"message": "read from file failed",
			"result":  nil,
		})
		log.WithField("error", err).Error("read from file failed")
		return
	}

	var params []common.ImportModuleParam
	for _, record := range records { // parent, name, desc
		if len(record) != 3 {
			c.PureJSON(http.StatusBadRequest, gin.H{
				"code":    common.ErrInvalidParam,
				"message": fmt.Sprintf("invalid param num:%d", len(record)),
				"result":  nil,
			})
			return
		}

		var param common.ImportModuleParam
		param.Parent = record[0]
		param.Name = record[1]
		param.Desc = record[2]
		params = append(params, param)

		log.WithField("param", common.MustMarshal(param)).Info("add import module param")
	}

	if err := core.ImportModules(params); err != nil {
		c.PureJSON(http.StatusBadRequest, gin.H{
			"code":    common.ErrInvalidParam,
			"message": err.Error(),
			"result":  nil,
		})
	} else {
		c.PureJSON(http.StatusOK, gin.H{
			"code":    0,
			"message": "success",
			"result":  nil,
		})
	}
}
